﻿package elements 
{
	import flash.display.DisplayObject;
	import flash.display.GradientType;
	import flash.display.Graphics;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;
	import styles.ButtonStyle;
	import styles.ScrollerStyle;
	
	/**
	 * Scroller!
	 * @author kasoi
	 */
	public class Scroller extends Sprite
	{
		static public const BUTTONS_WIDTH: Number = 8;
		
		////////////////////////////////////////////////////////////////////
		// Public properties
		////////////////////////////////////////////////////////////////////
		
		public function get progress() : Number
		{
			return this._progress;
		}
		
		public function set progress(value: Number) : void 
		{
			if (this._height > this._content.height) 
			{
				this._progress = 0;
				return;
			}
			this._progress = value;
			
			var h: Number = this._height;
			var bh: Number = this.downButton.height;
			var sh: Number = this.scroller.height;
			this.scroller.y = bh + (h - bh * 2 - sh) * value;
			
			this._content.y = ( -this._content.height + h) * value;
		}
		
		////////////////////////////////////////////////////////////////////
		// Private properties
		////////////////////////////////////////////////////////////////////
		
		private var upButton: Button;
		
		private var downButton: Button;
		
		private var scroller: Button;
		
		private var background: Sprite;
		
		private var isScrollerPressed: Boolean = false;
		
		private var currentPosition: Number;
		
		private var contentMask: Sprite;
		
		private var style: ScrollerStyle;
		
		private var _content: DisplayObject;
		
		private var _height: Number;
		
		private var _padding: Number;
		
		private var _progress: Number = 0;
		
		////////////////////////////////////////////////////////////////////
		// Public methods
		////////////////////////////////////////////////////////////////////
		
		public function Scroller(content: DisplayObject, height: Number, style: ScrollerStyle = null, padding:Number = 10 ) 
		{
			this._padding = padding;
			this._content = content;
			this._height = height;
			if (!style) style = new ScrollerStyle();
			this.style = style;
			
			this.background = new Sprite();
			this.background.graphics.beginFill(style.backgroundColor, 1);
			this.background.graphics.drawRect(0, 0, Scroller.BUTTONS_WIDTH, height);
			this.background.graphics.endFill();
			this.background.x = content.width+this._padding;
			
			this.contentMask = new Sprite();
			this.contentMask.graphics.beginFill(0xff00ff, 0.0);
			this.contentMask.graphics.drawRect(0, 0, this._content.width, this._height);
			this.contentMask.graphics.endFill();
			this.addChild(this.contentMask);
			
			this._content.mask = this.contentMask;
			this.addChild(this.background);
			this.addChild(this._content);
			
			this.initButtons();
			
			this.update();
		}
		
		public function remove() : void 
		{
			this.upButton.removeEventListener(MouseEvent.CLICK, this.upButton_onClick);
			this.downButton.removeEventListener(MouseEvent.CLICK, this.downButton_onClick);
			this.scroller.removeEventListener(MouseEvent.MOUSE_DOWN, this.scroller_onMouseDown);
			this.removeEventListener(Event.ADDED_TO_STAGE, this.this_onAddedToStage);
			this.removeEventListener(Event.ENTER_FRAME, this.this_onEnterFrame);
			this.removeEventListener(MouseEvent.MOUSE_WHEEL, this.this_onMouseWheel);
			
			if (stage)
			{
				if (stage.hasEventListener(MouseEvent.MOUSE_UP))
				{
					stage.removeEventListener(MouseEvent.MOUSE_UP, this.stage_onMouseUp);
				}
			}
			
			while (this.numChildren > 0)
			{
				this.removeChildAt(0);
			}
		}
		
		public function update() : void 
		{
			if (this._height >= this._content.height) 
			{
				this.scroller.visible = false;
				this.background.visible = false;
				this.upButton.visible = false;
				this.downButton.visible = false;
			}
			else 
			{
				this.scroller.visible = true;
				this.background.visible = true;
				this.upButton.visible = true;
				this.downButton.visible = true;
			}
		}
		
		////////////////////////////////////////////////////////////////////
		// Private methods
		////////////////////////////////////////////////////////////////////
		
		private function initButtons() : void 
		{
			// TODO: remove this shi-
			
			var buttonStyle: ButtonStyle = new ButtonStyle();
			//buttonStyle.activeColor = this.style.activeColor;
			//buttonStyle.hoverColor = this.style.hoverColor;
			//buttonStyle.hoverStyle = this.style.buttonStyle;
			
			var w: Number = Scroller.BUTTONS_WIDTH;
			var bh: Number = 8;
			this.upButton = new Button(this.createRoundRect(w, bh, this.style.normalColor), buttonStyle, false);
			this.downButton = new Button(this.createRoundRect(w, bh, this.style.normalColor), buttonStyle, false);
			
			var sh: Number = 60;
			if (sh + bh * 2 > this._height) sh = (this._height - bh * 2) / 2;
			this.scroller = new Button(this.createRoundRect(w, sh, this.style.normalColor), buttonStyle, false);
			this.scroller.y = this.upButton.y + this.upButton.height;
			
			this.downButton.y = this._height - this.downButton.height;
			this.scroller.x = this.upButton.x = this.downButton.x = this._content.width+this._padding;
			
			this.addChild(this.downButton);
			this.addChild(this.upButton);
			this.addChild(this.scroller);
			
			this.upButton.addEventListener(MouseEvent.CLICK, this.upButton_onClick);
			this.downButton.addEventListener(MouseEvent.CLICK, this.downButton_onClick);
			this.scroller.addEventListener(MouseEvent.MOUSE_DOWN, this.scroller_onMouseDown);
			this.addEventListener(Event.ADDED_TO_STAGE, this.this_onAddedToStage);
			this.addEventListener(Event.ENTER_FRAME, this.this_onEnterFrame);
			this.addEventListener(MouseEvent.MOUSE_WHEEL, this.this_onMouseWheel);
		}
		
		private function createRoundRect(width: Number, height: Number, 
			color: Number = 0xadadad, roundness: Number = 4) : Sprite
		{
			var spr: Sprite = new Sprite();
			spr.graphics.beginFill(color, 1);
			spr.graphics.drawRoundRect(0, 0, width, height, roundness, roundness);
			spr.graphics.endFill();
			
			return spr;
		}
		
		////////////////////////////////////////////////////////////////////
		// Listeners
		////////////////////////////////////////////////////////////////////
		
		private function this_onAddedToStage(e: Event) : void 
		{
			stage.addEventListener(MouseEvent.MOUSE_UP, this.stage_onMouseUp);
			this.update();
		}
		
		private function stage_onMouseUp(e: MouseEvent) : void 
		{
			if (!this.isScrollerPressed) return;
			this.isScrollerPressed = false;
			this.stopDrag();
		}
		
		private function scroller_onMouseDown(e: MouseEvent) : void 
		{
			this.isScrollerPressed = true;
			var x: Number = this.scroller.x;
			var y: Number = this.upButton.height + this.upButton.y;
			var w: Number = x;
			var h: Number = this._height - this.upButton.height 
				- this.downButton.height - this.scroller.height;
			this.scroller.startDrag(false, new Rectangle(x, y, 0, h));
		}
		
		private function upButton_onClick(e: MouseEvent) : void 
		{
			this.progress -= 0.05;
			if (this._progress <= 0) this.progress = 0;
		}
		
		private function downButton_onClick(e: MouseEvent) : void 
		{
			this.progress += 0.05;
			if (this._progress >= 1) this.progress = 1;
		}
		
		private function this_onEnterFrame(e: Event) : void 
		{
			if (this.isScrollerPressed)
			{
				if (this.scroller.y == this.currentPosition) return;
				this.currentPosition = this.scroller.y;
				
				var h: Number = this._height;
				var bh: Number = this.upButton.height;
				var scrollHeight: Number = this.scroller.height;
				var scrollY: Number = this.scroller.y;
				this._progress = (scrollY - bh) / (h - bh * 2 - scrollHeight)
				
				this._content.y = (-this._content.height + h) * this._progress;
				
				this.dispatchEvent(new Event(Event.CHANGE));
			}
		}
		
		private function this_onMouseWheel(e: MouseEvent) : void 
		{
			e.delta < 0 ? this.downButton_onClick(e) : this.upButton_onClick(e);
		}
	}
	
}